/*
 * 人人信用管理有限公司版权所有.
 * 
 * @Description:
 * 
 * @author: liyuliang
 * 
 * @date: 20 Apr 2017 10:44:16 am
 * 
 * 注意：本内容仅限于人人信用管理有限公司内部传阅，禁止外泄以及用于其他的商业目的.
 */

package com.rrx360.common.hibernate;

import java.io.Serializable;
import java.sql.Timestamp;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.hibernate.EmptyInterceptor;
import org.hibernate.type.Type;

import com.rrx360.common.model.Auditable;

public class AuditableInterceptor extends EmptyInterceptor {

  private static final long serialVersionUID = 4490506384449823933L;

  private Map<String, Integer> indexMap = new ConcurrentHashMap<>();

  private transient AuditInfoGetter auditInfoGetter;



  public AuditInfoGetter getAuditInfoGetter() {
    return auditInfoGetter;
  }

  public void setAuditInfoGetter(AuditInfoGetter auditInfoGetter) {
    this.auditInfoGetter = auditInfoGetter;
  }

  public Serializable getUserId() {
    if (auditInfoGetter != null) {
      return auditInfoGetter.getUserId();
    }
    return null;
  }

  @Override
  public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState,
      Object[] previousState, String[] propertyNames, Type[] types) {
    if (!(entity instanceof Auditable)) {
      return false;
    }
    Timestamp currentTime = new Timestamp(System.currentTimeMillis());
    int updatedOnIndex = getIndex(entity.getClass(), "updatedOn", propertyNames);
    int updatedByIndex = getIndex(entity.getClass(), "updatedBy", propertyNames);

    currentState[updatedOnIndex] = currentTime;
    Serializable currentUserId = getUserId();
    currentState[updatedByIndex] = currentUserId;
    return true;
  }


  @Override
  public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames,
      Type[] types) {
    if (!(entity instanceof Auditable)) {
      return false;
    }
    Timestamp currentTime = new Timestamp(System.currentTimeMillis());
    final int createdOnIndex = getIndex(entity.getClass(), "createdOn", propertyNames);
    final int updatedOnIndex = getIndex(entity.getClass(), "updatedOn", propertyNames);
    final int createdByIndex = getIndex(entity.getClass(), "createdBy", propertyNames);
    final int updatedByIndex = getIndex(entity.getClass(), "updatedBy", propertyNames);

    boolean change = false;
    if (state[createdOnIndex] == null) {
      state[createdOnIndex] = currentTime;
      change = true;
    }
    if (state[updatedOnIndex] == null) {
      state[updatedOnIndex] = currentTime;
      change = true;
    }
    Serializable currentUserId = getUserId();
    if (state[createdByIndex] == null) {
      state[createdByIndex] = currentUserId;
      change = true;
    }
    if (state[updatedByIndex] == null) {
      state[updatedByIndex] = currentUserId;
      change = true;
    }
    return change;
  }

  private Integer getIndex(Class clazz, String propertyName, String[] propertyNames) {
    String key = clazz.getName() + "_" + propertyName;
    Integer index = indexMap.get(key);
    if (index != null) {
      return index;
    }
    for (int i = 0; i < propertyNames.length; i++) {
      if (propertyNames[i].equals(propertyName)) {
        index = i;
        indexMap.put(key, index);
      }
    }
    return index;

  }


}
